/*******************************************************************************
 *
 * A blank reference implementation exists below. Replace it with your
 * implementation.
 *
 *                                                                        [n=80]
 ******************************************************************************/

module.exports = (function() {
  "use strict";

  var dowParser = require("../lib/dowParser");
  var TimeIntervalList = require("../lib/timeIntervalList");


  var phraseRE2csrc = "(" + dowParser.listREsrc +")|(" +
    TimeIntervalList.REsrc + ")";


  var hours = {};
  hours.parse = function(text) {
    function parsePhrases(text, results) {
      var phraseRE2c = new RegExp(phraseRE2csrc, "ig");
      var currDOWrangesText;
      var match;
      while ((match = phraseRE2c.exec(text))) {
        var dowRangesText = match[1];
        var hoursRangesText = match[2];

        if (dowRangesText !== undefined) {
          currDOWrangesText = dowRangesText;
          continue;
        }

        if (hoursRangesText !== undefined) {
          if (currDOWrangesText === undefined)
            continue; // skip hours spec without preceding DOW spec

          parseDOWhours(currDOWrangesText, hoursRangesText, results)
        }
      }
    }

    function parseDOWhours(dowRangesText, hoursRangesText, results) {
      var dows = parseDOWranges(dowRangesText);
      var hoursRanges = TimeIntervalList.parse(hoursRangesText);

      if (hoursRanges.length() < 1) return;

      for (var d=0; d<7; ++d) {
        if (!dows[d])
          continue;

        if (!results[d])
          results[d] = new TimeIntervalList();

        results[d].addList(hoursRanges);
      }
    }

    function parseDOWranges(text) {
      // return an array, populated with Boolean 'true' entries at indices
      // indicating the days of weeks as specified in <text>.
      // e.g. if "Tue" is specified, returned_value[2] will be 'true';
      var parser = dowParser.chooseInstance(text);

      var dow = [];
      var dowRangesText = text.split(parser.listDelimRE);
      for (var i in dowRangesText) {
        var rangeText = dowRangesText[i];
        var match = rangeText.match(parser.rangeREc2);
        if (!match) {
          continue; // skip unrecognized parts (e.g. "PH")
        }

        var start = match[1];
        // trim trailing '.', etc.
        start = start && parser.convert2num(start);
        var end = match[2];
        end = end && parser.convert2num(end);
        if (end === undefined)
          end = start;

        if (typeof(start) !== "number") { // assume start == [a,b]
          end = start[1];
          start = start[0];
        }

        var d = start;
        for (;;) {
          dow[d] = true;
          if (d === end) break;
          d = (d+1) % 7;
        }
      }
      return dow;
    }


    function formatResults(results) {
      var dowDone = [];
      for (var d=0; d<7; ++d)
        if (results[d] === undefined)
          dowDone[d] = true;

      var strs = [];

      for (;;) { // find a result item to format
        var i = 0;
        while (i < 7 && dowDone[i])
          ++i
        if (i >= 7) break; // all done
        var curr = results[i];

        // find other items with identical time intervals
        var currentDOWs = [];
        currentDOWs[i] = true;
        dowDone[i] = true;
        for (var j=i+1; j<7; ++j) {
          if (!dowDone[j] && curr.equals(results[j])) {
            currentDOWs[j] = true;
            dowDone[j] = true;
          }
        }

        strs.push(formatDOWs(currentDOWs) + ":" + curr);
      }

      return "S" + strs.join(";");
    }

    function formatDOWs(dows) {
      var strs = [];

      for (;;) {
        // find first empty entry
        var empty1 = 0;
        while (empty1 < 7 && dows[empty1])
          ++empty1;

        // determine first non-empty item after the 'empty1'
        var nonEmpty1;
        if (empty1 >= 7) { // no empty entry in dows[]
          nonEmpty1 = 0;
        } else {
          nonEmpty1 = (empty1+1) % 7;
          while (nonEmpty1 !== empty1) {
            if (dows[nonEmpty1])
              break;
            nonEmpty1 = (nonEmpty1+1) % 7;
          }

          if (nonEmpty1 === empty1) { // no more non-empty dows entry
            return strs.join(",");
          }
        }

        var d = nonEmpty1;
        for (;;) {
          if (!dows[d]) {
            break;
          }

          dows[d] = false;
          d = (d + 1) % 7;
        }

        d = (d+6)%7;

        if (nonEmpty1 === d) {
          strs.push(nonEmpty1);
        } else {
          strs.push(nonEmpty1 + "-" + d);
        }
      }
    }

    var results = [];
    parsePhrases(text, results);
    return formatResults(results);
  }

  return hours

}());

